我想要在我的頁面中放進去一個影片預告片的內容
這次會用到Appple的原生Module: AVFoundation
專門在處理影片相關的內容
先創立一個View來作為播放的View
import AVFoundation
import UIKit
class VideoView: UIView {
private var playerItemContext = 0
override class var layerClass: AnyClass {
return AVPlayerLayer.self
}
var player: AVPlayer? {
get {
return playerLayer.player
} set {
return playerLayer.player = newValue
}
}
private func initPlayerAsset(with url: URL, completion: ((_ assets: AVAsset) -> Void)?) {
let assets = AVAsset(url: url)
assets.loadValuesAsynchronously(forKeys: ["playable"]) {
completion?(asset)
}
}
func play(with url: URL) {
initPlayerAsset(with: url) { (asset: AVAsset) in
let item = AVPlayerItem(asset: asset)
// KVO,註冊通知
item.addObserver(self, forKeyPath: #keyPath(AVPlayerItem.status), option: [.old, .new], context: &self.playerItemContext)
DispatchQueue.main.async {
self.player = AVPlayer(playerItem: item)
}
}
}
// Observe接收到通知後,就會執行這段
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey: Any]?, context: UnsafeMutableRawPointer? ) {
guard context != &self.playerItemContext else {
super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
return
}
if keyPath == #keyPath(AVPlayerItem.status) {
let status: AVPlayerItem.Status
if let statusNumber = change?[.newKey] as? NSNumber {
status = AVPlayerItem.Status(rawValue: statusNumber.initValue)!
} else {
status = .unknown
}
// 用來判斷目前的狀態
switch status {
case .readyToPlay:
self.player?.play()
print("Ready to play")
case .failed:
print("Failed")
case .unknown:
print("Unknow")
@unknown default:
print("Unknow Failed")
}
}
}
}
因為我要放在tableViewCell內部所以我拉一個View在tableViewCell內部,將該View CustomClass改成VideoView
再加入一個Button按鈕作為開始/暫停的控制按鈕
記得將初始化的Code也一併寫入
//tableViewCell.swift
@IBOutlet weak var videoView: VideoView!
@IBOutlet weak var controlButton: UIButton! {
didSet {
controlButton.addTarget(self, action: #selector(switchControl), for: .touchUpInside)
}
}
// 開始/暫停開關Func
@objc func switchControl() {
if controlButton.titleLabel?.text == "Pause" {
video.player?.pause()
controlButton.setTitle("Start", for: .normal)
} else {
video.player?.start()
controlButton.setTitle("Pause", for: .normal)
}
}
.
.
.
func configure(url: URL) {
// 影片初始化流程(含開始播放)
videoView.play(with: url)
}
這樣就可以完美的把影片播出來,只是其他細節設定都還沒處理
參考資料:
https://medium.com/@tarasuzy00/build-video-player-in-ios-i-avplayer-43cd1060dbdc
https://www.jianshu.com/p/20e5e6d5f3e5
坑:
原本看到override class var layerClass的時候有點不明所以,所以忽略不寫
但是後來發現要先將自身的layer轉型成AVPlayerLayer才能夠使用